package ch.fusun.baron.player;

import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

import org.eclipse.core.runtime.FileLocator;
import org.eclipse.core.runtime.Path;
import org.osgi.framework.Bundle;

import ch.fusun.baron.core.rmi.User;
import ch.fusun.baron.data.AbstractDataProvider;
import ch.fusun.baron.data.DataUpdate;
import ch.fusun.baron.player.api.PlayerService;
import ch.fusun.baron.player.api.PlayerUpdate;

/**
 * Service for the management of {@link Player}s
 */
public class PlayerServiceImpl extends AbstractDataProvider implements
		PlayerService {

	private Map<Dynasty, User> dynasties = new HashMap<Dynasty, User>();
	private final List<String> maleNames = new ArrayList<String>();
	private final List<String> femaleNames = new ArrayList<String>();
	private int idCounter = 0;

	/**
	 * Constructor
	 */
	public PlayerServiceImpl() {
		loadNames("resources/names/male.txt", maleNames); //$NON-NLS-1$
		loadNames("resources/names/female.txt", femaleNames); //$NON-NLS-1$
	}

	private static void loadNames(String location, List<String> list) {
		Bundle bundle = Activator.getContext().getBundle();
		Path path = new Path(location);
		URL url = FileLocator.find(bundle, path, Collections.EMPTY_MAP);
		URL fileUrl = null;
		try {
			fileUrl = FileLocator.toFileURL(url);
		} catch (IOException e) {
			// Will happen if the file cannot be read for some reason
			e.printStackTrace();
			return;
		}

		FileInputStream in;
		try {
			in = new FileInputStream(fileUrl.getPath());
			BufferedReader br = new BufferedReader(new InputStreamReader(in));
			String strLine;
			do {
				strLine = br.readLine();
				list.add(strLine);
			} while (strLine != null);
			in.close();
		} catch (Exception e) {
			list.add("Eveline Widmer-Schlumpf"); //$NON-NLS-1$
			e.printStackTrace();
		}
	}

	@Override
	public DataUpdate createFullUpdate() {
		return new PlayerUpdate(dynasties);
	}

	@Override
	public List<Player> getPlayers(User user) {
		List<Player> playersPerUser = new ArrayList<Player>();
		for (Dynasty dynasty : dynasties.keySet()) {
			User temp = dynasties.get(dynasty);
			if (user.equals(temp)) {
				playersPerUser.addAll(dynasty.getMembers());
			}
		}
		return playersPerUser;
	}

	@Override
	public void setDynasties(Map<Dynasty, User> dynasties) {
		this.dynasties = dynasties;
		updateAllListeners(new SetDynastiesUpdate(dynasties));
	}

	@Override
	public void setDynastyForUser(Dynasty player, User user) {
		dynasties.put(player, user);
		updateAllListeners(new SetDynastyForUserDataUpdate(player, user));
	}

	@Override
	public List<Player> getAllPlayers() {
		List<Player> result = new LinkedList<Player>();
		for (Dynasty dynasty : dynasties.keySet()) {
			result.addAll(dynasty.getMembers());
		}
		return result;
	}

	@Override
	public User getUser(Dynasty dynasty) {
		return dynasties.get(dynasty);
	}

	@Override
	public Dynasty getDynasty(User user) {
		for (Dynasty dynasty : dynasties.keySet()) {
			User temp = dynasties.get(dynasty);
			if (user.equals(temp)) {
				return dynasty;
			}
		}
		return null;
	}

	@Override
	public List<Dynasty> getAllDynasties() {
		List<Dynasty> result = new LinkedList<Dynasty>();
		result.addAll(dynasties.keySet());
		return result;
	}

	@Override
	public Dynasty getDynasty(Player player) {
		for (Dynasty dynasty : dynasties.keySet()) {
			if (dynasty.getMembers().contains(player)) {
				return dynasty;
			}
		}
		return null;
	}

	@Override
	public String generateName(Gender gender) {
		if (Gender.MALE.equals(gender)) {
			return maleNames.get((int) (Math.random() * maleNames.size()));
		}
		if (Gender.FEMALE.equals(gender)) {
			return femaleNames.get((int) (Math.random() * femaleNames.size()));
		}
		return "Christoph Blocher"; //$NON-NLS-1$
	}

	@Override
	public void addPlayerToDynasty(Dynasty dynasty, Player child) {
		for (Dynasty old : dynasties.keySet()) {
			if (old.equals(dynasty)) {
				old.addPlayer(child);
				updateAllListeners(new AddPlayerToDynastyDataUpdate(dynasty,
						child));
				return;
			}
		}
	}

	@Override
	public Player generateNewPlayer(Gender gender) {
		return new Player(idCounter++, generateName(gender), gender);
	}

	@Override
	public void updatePlayer(Player person) {
		for (Dynasty dynasty : dynasties.keySet()) {
			dynasty.updatePerson(person);
		}
		updateAllListeners(new UpdatePlayerUpdateData(person));
	}

	@Override
	public void removePlayers(List<Player> playersToRemove) {
		for (Dynasty dynasty : dynasties.keySet()) {
			for (Player player : playersToRemove) {
				dynasty.removePerson(player);
			}
		}
		updateAllListeners(new RemovePlayerUpdateData(playersToRemove));
	}
}
